From a582b2638b99da60e50976b8393183d54ddb9ede Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Thu, 16 Feb 2006 18:52:06 +0100 Subject: [PATCH] New memory_op subcall XENMEM_translate_gpfn_list. Allows translation from GPFNs to MFNs for an auto-translated guest. Signed-off-by: Keir Fraser --- tools/libxc/xc_domain.c | 47 +++++++++++++++++++ tools/libxc/xc_private.c | 26 ++++++++++ tools/libxc/xenctrl.h | 13 +++++ xen/common/memory.c | 94 +++++++++++++++++++++++++++++++++---- xen/include/public/memory.h | 24 +++++++++- 5 files changed, 195 insertions(+), 9 deletions(-) diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c index 89bdb86e5d..ea2ca76d1b 100644 --- a/tools/libxc/xc_domain.c +++ b/tools/libxc/xc_domain.c @@ -326,6 +326,53 @@ int xc_domain_memory_decrease_reservation(int xc_handle, return err; } +int xc_domain_memory_populate_physmap(int xc_handle, + uint32_t domid, + unsigned long nr_extents, + unsigned int extent_order, + unsigned int address_bits, + unsigned long *extent_start) +{ + int err; + struct xen_memory_reservation reservation = { + .extent_start = extent_start, + .nr_extents = nr_extents, + .extent_order = extent_order, + .address_bits = address_bits, + .domid = domid + }; + + err = xc_memory_op(xc_handle, XENMEM_populate_physmap, &reservation); + if ( err == nr_extents ) + return 0; + + if ( err > 0 ) + { + fprintf(stderr,"Failed deallocation for dom %d: %ld pages order %d\n", + domid, nr_extents, extent_order); + errno = EBUSY; + err = -1; + } + + return err; +} + +int xc_domain_translate_gpfn_list(int xc_handle, + uint32_t domid, + unsigned long nr_gpfns, + unsigned long *gpfn_list, + unsigned long *mfn_list) +{ + struct xen_translate_gpfn_list op = { + .domid = domid, + .nr_gpfns = nr_gpfns, + .gpfn_list = gpfn_list, + .mfn_list = mfn_list + }; + + return xc_memory_op(xc_handle, XENMEM_translate_gpfn_list, &op); +} + int xc_domain_max_vcpus(int xc_handle, uint32_t domid, unsigned int max) { DECLARE_DOM0_OP; diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c index 70d5d6829a..edf55d360c 100644 --- a/tools/libxc/xc_private.c +++ b/tools/libxc/xc_private.c @@ -191,6 +191,7 @@ int xc_memory_op(int xc_handle, DECLARE_HYPERCALL; struct xen_memory_reservation *reservation = arg; struct xen_machphys_mfn_list *xmml = arg; + struct xen_translate_gpfn_list *trans = arg; long ret = -EINVAL; hypercall.op = __HYPERVISOR_memory_op; @@ -237,6 +238,26 @@ int xc_memory_op(int xc_handle, goto out1; } break; + case XENMEM_translate_gpfn_list: + if ( mlock(trans, sizeof(*trans)) != 0 ) + { + PERROR("Could not mlock"); + goto out1; + } + if ( mlock(trans->gpfn_list, trans->nr_gpfns * sizeof(long)) != 0 ) + { + PERROR("Could not mlock"); + safe_munlock(trans, sizeof(*trans)); + goto out1; + } + if ( mlock(trans->mfn_list, trans->nr_gpfns * sizeof(long)) != 0 ) + { + PERROR("Could not mlock"); + safe_munlock(trans->gpfn_list, trans->nr_gpfns * sizeof(long)); + safe_munlock(trans, sizeof(*trans)); + goto out1; + } + break; } ret = do_xen_hypercall(xc_handle, &hypercall); @@ -259,6 +280,11 @@ int xc_memory_op(int xc_handle, case XENMEM_reserved_phys_area: safe_munlock(arg, sizeof(struct xen_reserved_phys_area)); break; + case XENMEM_translate_gpfn_list: + safe_munlock(trans->mfn_list, trans->nr_gpfns * sizeof(long)); + safe_munlock(trans->gpfn_list, trans->nr_gpfns * sizeof(long)); + safe_munlock(trans, sizeof(*trans)); + break; } out1: diff --git a/tools/libxc/xenctrl.h b/tools/libxc/xenctrl.h index dc6a9c0f83..282a6f9e67 100644 --- a/tools/libxc/xenctrl.h +++ b/tools/libxc/xenctrl.h @@ -373,6 +373,19 @@ int xc_domain_memory_decrease_reservation(int xc_handle, unsigned int extent_order, unsigned long *extent_start); +int xc_domain_memory_populate_physmap(int xc_handle, + uint32_t domid, + unsigned long nr_extents, + unsigned int extent_order, + unsigned int address_bits, + unsigned long *extent_start); + +int xc_domain_translate_gpfn_list(int xc_handle, + uint32_t domid, + unsigned long nr_gpfns, + unsigned long *gpfn_list, + unsigned long *mfn_list); + int xc_domain_ioport_permission(int xc_handle, uint32_t domid, uint32_t first_port, diff --git a/xen/common/memory.c b/xen/common/memory.c index 320e8c3d6e..40a2d9c14d 100644 --- a/xen/common/memory.c +++ b/xen/common/memory.c @@ -20,6 +20,13 @@ #include #include +/* + * To allow safe resume of do_memory_op() after preemption, we need to know + * at what point in the page list to resume. For this purpose I steal the + * high-order bits of the @cmd parameter, which are otherwise unused and zero. + */ +#define START_EXTENT_SHIFT 4 /* cmd[:4] == start_extent */ + static long increase_reservation( struct domain *d, @@ -188,17 +195,74 @@ decrease_reservation( return nr_extents; } -/* - * To allow safe resume of do_memory_op() after preemption, we need to know - * at what point in the page list to resume. For this purpose I steal the - * high-order bits of the @cmd parameter, which are otherwise unused and zero. - */ -#define START_EXTENT_SHIFT 4 /* cmd[:4] == start_extent */ +static long +translate_gpfn_list( + struct xen_translate_gpfn_list *uop, unsigned long *progress) +{ + struct xen_translate_gpfn_list op; + unsigned long i, gpfn, mfn; + struct domain *d; + + if ( copy_from_user(&op, uop, sizeof(op)) ) + return -EFAULT; + + /* Is size too large for us to encode a continuation? */ + if ( op.nr_gpfns > (ULONG_MAX >> START_EXTENT_SHIFT) ) + return -EINVAL; + + if ( !array_access_ok(op.gpfn_list, op.nr_gpfns, sizeof(*op.gpfn_list)) || + !array_access_ok(op.mfn_list, op.nr_gpfns, sizeof(*op.mfn_list)) ) + return -EFAULT; -long do_memory_op(int cmd, void *arg) + if ( op.domid == DOMID_SELF ) + op.domid = current->domain->domain_id; + else if ( !IS_PRIV(current->domain) ) + return -EPERM; + + if ( (d = find_domain_by_id(op.domid)) == NULL ) + return -ESRCH; + + if ( !shadow_mode_translate(d) ) + { + put_domain(d); + return -EINVAL; + } + + for ( i = *progress; i < op.nr_gpfns; i++ ) + { + if ( hypercall_preempt_check() ) + { + put_domain(d); + *progress = i; + return -EAGAIN; + } + + if ( unlikely(__copy_from_user(&gpfn, &op.gpfn_list[i], + sizeof(gpfn))) ) + { + put_domain(d); + return -EFAULT; + } + + mfn = gmfn_to_mfn(d, gpfn); + + if ( unlikely(__copy_to_user(&op.mfn_list[i], &mfn, + sizeof(mfn))) ) + { + put_domain(d); + return -EFAULT; + } + } + + put_domain(d); + return 0; +} + +long do_memory_op(unsigned long cmd, void *arg) { struct domain *d; - int rc, start_extent, op, flags = 0, preempted = 0; + int rc, op, flags = 0, preempted = 0; + unsigned long start_extent, progress; struct xen_memory_reservation reservation; domid_t domid; @@ -212,6 +276,10 @@ long do_memory_op(int cmd, void *arg) if ( copy_from_user(&reservation, arg, sizeof(reservation)) ) return -EFAULT; + /* Is size too large for us to encode a continuation? */ + if ( reservation.nr_extents > (ULONG_MAX >> START_EXTENT_SHIFT) ) + return -EINVAL; + start_extent = cmd >> START_EXTENT_SHIFT; if ( unlikely(start_extent > reservation.nr_extents) ) return -EINVAL; @@ -302,6 +370,16 @@ long do_memory_op(int cmd, void *arg) break; + case XENMEM_translate_gpfn_list: + progress = cmd >> START_EXTENT_SHIFT; + rc = translate_gpfn_list(arg, &progress); + if ( rc == -EAGAIN ) + return hypercall2_create_continuation( + __HYPERVISOR_memory_op, + op | (progress << START_EXTENT_SHIFT), + arg); + break; + default: rc = arch_memory_op(op, arg); break; diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h index 3f24bb5386..eb99be99ef 100644 --- a/xen/include/public/memory.h +++ b/xen/include/public/memory.h @@ -101,7 +101,7 @@ typedef struct xen_machphys_mfn_list { */ #define XENMEM_reserved_phys_area 7 typedef struct xen_reserved_phys_area { - /* Which request to report about? */ + /* Which domain to report about? */ domid_t domid; /* @@ -114,6 +114,28 @@ typedef struct xen_reserved_phys_area { unsigned long first_gpfn, nr_gpfns; } xen_reserved_phys_area_t; +/* + * Translates a list of domain-specific GPFNs into MFNs. Returns a -ve error + * code on failure. This call only works for auto-translated guests. + */ +#define XENMEM_translate_gpfn_list 8 +typedef struct xen_translate_gpfn_list { + /* Which domain to translate for? */ + domid_t domid; + + /* Length of list. */ + unsigned long nr_gpfns; + + /* List of GPFNs to translate. */ + unsigned long *gpfn_list; + + /* + * Output list to contain MFN translations. May be the same as the input + * list (in which case each input GPFN is overwritten with the output MFN). + */ + unsigned long *mfn_list; +} xen_translate_gpfn_list_t; + #endif /* __XEN_PUBLIC_MEMORY_H__ */ /* -- 2.30.2